import { 
  AdditiveBlending,
  AmbientLight,
  Color,
  Group,
  Mesh,
  MeshNormalMaterial,
  PerspectiveCamera, 
  Points, 
  PointsMaterial, 
  Scene, 
  SpotLight, 
  Sprite, 
  SpriteMaterial, 
  Texture, 
  TextureLoader, 
  TorusKnotGeometry, 
  Vector2, 
  WebGLRenderer
} from "three"
import { TrackballControls } from 'three/examples/jsm/controls/TrackballControls'
import stats from "../utils/stats"
import dat from 'dat.gui'

const scene = new Scene()
const camera = new PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 1000)
camera.position.set(-20, 12, 200)
camera.lookAt(0, 0, 0)

const renderer = new WebGLRenderer({ antialias: true })
renderer.setClearColor(0x000000)
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)

const ambient = new AmbientLight(0x0c0c0c)
scene.add(ambient)

const spotlight = new SpotLight(0xffffff)
spotlight.position.set(100, 100, 100)
scene.add(spotlight)
// scene.add(new SpotLightHelper(spotlight))

let group :Group
const controls = {
  animate: true,
  radius: 13,
  tube: 1.7,
  tubularSegments: 12,
  radialSegments: 156,
  asParticles: true,
  q: 5,
  p: 4,

  draw() {
    scene.remove(group)
    group = new Group()
    
    // https://threejs.org/docs/index.html#api/zh/geometries/TorusKnotGeometry
    let geom = new TorusKnotGeometry(this.radius, this.tube, this.radialSegments, this.tubularSegments, this.p, this.q)

    if (this.asParticles) {
      group.add(createPoints(geom))
    } else {
      group.add(new Mesh(geom, new MeshNormalMaterial()))
    }

    scene.add(group)
  }
}

controls.draw()

const gui = new dat.GUI()
gui.add(controls, 'animate')
gui.add(controls, 'asParticles').onChange(controls.draw.bind(controls))
gui.add(controls, 'radius', 0, 40, 1).onChange(controls.draw.bind(controls))
gui.add(controls, 'p', 0, 40, 1).onChange(controls.draw.bind(controls))
gui.add(controls, 'q', 0, 40, 1).onChange(controls.draw.bind(controls))
gui.add(controls, 'tube', 0, 40).onChange(e => controls.draw())
gui.add(controls, 'radialSegments', 0, 400, 1).onChange(e => controls.draw())
gui.add(controls, 'tubularSegments', 1, 20, 1).onChange(e => controls.draw())

const trackballControls = new TrackballControls(camera, renderer.domElement)

function render() {
  stats.update()
  trackballControls.update()

  if (controls.animate) {
    group.rotation.x += 0.01
    group.rotation.z += 0.01
  }

  requestAnimationFrame(render)
  renderer.render(scene, camera)
}
render()


function generateSprite() {
  let canvas = document.createElement('canvas')
  canvas.width = 16
  canvas.height = 16

  let context = <CanvasRenderingContext2D>canvas.getContext('2d');
  // 方法创建放射状/圆形渐变对象
  // https://www.w3school.com.cn/tags/canvas_createradialgradient.asp
  let halfWidth = canvas.width /2
  let halfHeight = canvas.height/2
  let gradient = context.createRadialGradient(halfWidth, halfHeight, 0, halfWidth, halfHeight, halfWidth)
  gradient.addColorStop(0, 'rgba(255, 255, 255, 1)')
  gradient.addColorStop(0.2, 'rgba(0, 255, 255, 1)')
  gradient.addColorStop(0.4, 'rgba(0, 0, 64, 1)')
  gradient.addColorStop(1, 'rgba(0, 0, 0, 1)')

  context.fillStyle = gradient
  context.fillRect(0, 0, canvas.width, canvas.height)

  let texture = new Texture(canvas)
  texture.needsUpdate = true
  return texture
}

function createPoints(geom) {
  let material = new PointsMaterial({
    color: 0xffffff,
    size: 3,
    transparent: true,
    blending: AdditiveBlending,
    map: generateSprite(),
    depthWrite: false
  })

  // 使用几何体生成粒子系统
  let cloud = new Points(geom, material)
  return cloud
}